/* Copyright (c) 2012 William Steven Knauer
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.williamknauer.android.yagol;

import android.os.SystemClock;

/**
 * A simple fixed-delta updater class. Use by overriding {@code update()}.
 * 
 * @author William S Knauer <knauerw1@gmail.com>
 * @version 2012.0111
 */
public abstract class GameUpdater extends Thread {
	private volatile boolean mCompleted;
	private volatile boolean mPaused;
	private volatile boolean mTerminate;
	private volatile long mDelta;

	public GameUpdater(long delta) {
		super();
		mCompleted = false;
		mDelta = delta;
		mPaused = true;
		mTerminate = false;
	}

	@Override
	public void run() {
		/*
		 * Run until signaled to terminate.
		 */
		while (!mTerminate && !mCompleted) {
			/*
			 * Execute update loop until it is paused.
			 */
			runLoop();

			/*
			 * We're in an infinite loop, so yield.
			 */
			synchronized (this) {
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		mCompleted = true;
	}

	protected abstract void update();

	private void runLoop() {
		long nextUpdate = SystemClock.uptimeMillis();
		/*
		 * Loop until paused.
		 */
		while (!mPaused) {
			/*
			 * Call update if the delta has elapsed.
			 */
			if (SystemClock.uptimeMillis() >= nextUpdate) {
				update();
				nextUpdate += mDelta;
			} else {
				try {
					/*
					 * Wait around for the next delta.
					 */
					Thread.sleep(nextUpdate - SystemClock.uptimeMillis());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public synchronized void terminate() {
		mTerminate = true;
	}

	@Override
	public synchronized void start() {
		play();
	}

	public synchronized void play() {
		mPaused = false;
		this.notifyAll();
		/*
		 * Guard for restarting dead updater threads.
		 */
		if (!isAlive() && !mCompleted) {
			super.start();
		}
	}

	public synchronized void pause() {
		mPaused = true;
	}

	public boolean isPaused() {
		return mPaused;
	}

	public synchronized void setDelta(long delta) {
		mDelta = delta;
	}

}